/*
 * Copyright (C), 2014-2016, org.esaydev
 * FileName: WechatClient.java
 * Author:   jian
 * Date:     2016年3月18日 
 */
package org.easydev.wechat.client;

import org.apache.commons.lang3.StringUtils;
import org.easydev.wechat.annotation.RequestRef;
import org.easydev.wechat.client.dto.base.AccessToken;
import org.easydev.wechat.client.dto.base.BaseParam;
import org.easydev.wechat.client.handle.WechatRequestHandle;
import org.easydev.wechat.client.result.base.AccessTokenResult;
import org.easydev.wechat.client.result.base.BaseWechatResult;
import org.easydev.wechat.client.util.WechatReqConfig;
import org.easydev.wechat.client.util.WechatReqUtil;
import org.easydev.wechat.common.constants.WechatConfig;
import org.easydev.wechat.common.constants.WechatErrorCode;
import org.easydev.wechat.common.exception.WechatException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <Description> <br>
 * 
 * @author jian<br>
 * @version 1.0<br>
 */
public class WechatClient {

    /**
     * static LOGGER
     */
    private static Logger LOGGER = LoggerFactory.getLogger(WechatClient.class);

    /**
     * 服务配置文件
     */
    private static final String SERVICE_FILE = "service.json";

    /**
     * wechatClient
     */
    private static WechatClient wechatClient;

    /**
     * accessToken
     */
    private static String accessToken = StringUtils.EMPTY;

    /**
     * tonken生成时间
     */
    private static long tokenGenerateTime = System.currentTimeMillis();

    /**
     * 初始化客户端实例，注册微信服务
     */
    private WechatClient() {
        LOGGER.info("[init wechat client] begin ...");
        WechatReqUtil.registService(SERVICE_FILE);
        LOGGER.info("[init wechat client] end ...");
    }

    /**
     * Description: 获取微信客户端实例<br>
     * 
     * @return <br>
     */
    public static WechatClient getInstance() {
        if (null == wechatClient) {
            synchronized (WechatClient.class) {
                if (null == wechatClient) {
                    wechatClient = new WechatClient();
                }
            }
        }
        return wechatClient;
    }

    /**
     * Description: 调用微信获取结果<br>
     * 
     * @param param <br>
     * @return <br>
     * @throws WechatException <br>
     */
    public BaseWechatResult getFromWechat(BaseParam param) throws WechatException {
        if (!param.getClass().isAnnotationPresent(RequestRef.class)) {
            throw new WechatException(WechatErrorCode.PARAMS_ERROR);
        }
        if (StringUtils.isBlank(param.getAccessToken())) {
            param.setAccessToken(getAcceccToken());
        }
        WechatRequestHandle handler = null;
        WechatReqConfig objConfig = null;
        try {
            RequestRef reqType = param.getClass().getAnnotation(RequestRef.class);
            objConfig = WechatReqUtil.getWechatConfig(reqType.value());
            handler = WechatReqUtil.getMappingHander(objConfig.getMappingHandler());
        } catch (Exception e) {
            throw new WechatException(e);
        }
        if (null == handler || null == objConfig) {
            throw new WechatException(WechatErrorCode.PARAMS_ERROR);
        }
        return handler.doRequest(param, objConfig);
    }

    /**
     * Description: 获取AcceccToken<br>
     * 
     * @return <br>
     * @throws WechatException <br>
     */
    public synchronized String getAcceccToken() throws WechatException {
        if (System.currentTimeMillis() < tokenGenerateTime + 60 * 60 * 1000 && StringUtils.isNotBlank(accessToken)) {
            return accessToken;
        } else {
            AccessToken accessTokenParam = new AccessToken();
            accessTokenParam.setAppId(WechatConfig.getAppId());
            accessTokenParam.setSecret(WechatConfig.getAppSecret());
            WechatReqConfig objConfig = WechatReqUtil.getWechatConfig("token");
            WechatRequestHandle handler = WechatReqUtil.getMappingHander(objConfig.getMappingHandler());
            if (null == objConfig || null == handler) {
                throw new WechatException(WechatErrorCode.PARAMS_ERROR);
            }
            BaseWechatResult baseWechatResult = handler.doRequest(accessTokenParam, objConfig);
            if (baseWechatResult.isSuccess()) {
                accessToken = baseWechatResult.getData(AccessTokenResult.class).getAccessToken();
            }
            return accessToken;
        }
    }
}
